#pragma once
#include<iostream>


using namespace std;

namespace smart_ptr
{
	template<class T>
	class auto_ptr
	{
	public:

		auto_ptr(T* ptr )
			:_ptr(ptr)
		{}
		~auto_ptr()
		{
			cout << "~auto_ptr()" << endl;
			delete _ptr;
		}

		T* operator->()
		{
			return _ptr;
		}
		T operator*()
		{
			return *_ptr;
		}

		auto_ptr(auto_ptr<T>& ap)
			:_ptr(ap._ptr)
		{
			ap._ptr = nullptr;
		}
	private:
		T* _ptr;
	};

	template<class T>
	class unique_ptr
	{
	public:

		unique_ptr(T* ptr)
			:_ptr(ptr)
		{}


		unique_ptr(unique_ptr<T>&& ptr)
			:_ptr(ptr._ptr)
		{}
		
		~unique_ptr()
		{
			cout << "~unique_ptr()" << endl;

			delete _ptr;

		}
		T* operator->()
		{
			return _ptr;
		}
		T operator*()
		{
			return *_ptr;
		}

		unique_ptr<T>& operator=(const unique_ptr<T>& up) = delete;
		unique_ptr(const unique_ptr<T>& up) = delete;


	private:
		T* _ptr;
	};


	template<class T>
	class share_ptr
	{
	public:
		
		share_ptr(T* ptr)
			:_ptr(ptr)
			,_count(new int(1))
		{}


		~share_ptr()
		{
			if (--(*_count) == 0)
			{
				cout << "~share_ptr()" << endl;
				delete _ptr;
				delete _count;
			}
		}

		share_ptr<T>(const share_ptr<T>& sp)
			:_ptr(sp._ptr)
			,_count(sp._count)

		{
			++(*_count);
		}

		share_ptr<T>& operator=(const share_ptr<T>& sp)
		{
			_ptr = sp._ptr;
			_count = sp._count;
			++(*_count);

			return *this;
		}

		T* operator->()
		{
			return _ptr;
		}
		T operator*()
		{
			return *_ptr;
		}
		int use_count()const 
		{
			return *_count;
		}

		T* get()const
		{
			return _ptr;
		}
	private:
		T* _ptr;
		int* _count;
	};


	template<class T>
	class weak_ptr
	{
	public:
		weak_ptr()
			:_ptr(nullptr)
		{}

		weak_ptr(const share_ptr<T>& sp)
			:_ptr(sp.get())
		{}
		weak_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
			return *this;
		}

		T* operator->()
		{
			return _ptr;
		}
		T operator*()
		{
			return *_ptr;
		}


	private:
		T* _ptr;
	};
}